<?php
namespace Transparency;

use GuzzleHttp\HandlerStack;
use GuzzleHttp\Client as GuzzleHttpClient;
use GuzzleHttp\Middleware;
use GuzzleHttp\RequestOptions;
use Transparency\Errors\TransparencyException;
use Transparency\Resources\Codes;
use Psr\Http\Message\RequestInterface;

/**
 * @property-read Codes $codes
 */
class Client
{
    public CONST DEFAULT_VERSION = 'v1';
    protected string $client_id;
    protected string $client_secret;
    protected string $access_token;

    protected string $version;

    /**
     * custom guzzle client options
     *
     * @var array
     * @see https://docs.guzzlephp.org/en/stable/request-options.html
     */
    protected array $options;

    public const resources = [
        Codes::class,
    ];

    public function __construct($client_id, $client_secret, $options = [])
    {
        $this->client_id = $client_id;
        $this->client_secret = $client_secret;
        $this->version = static::DEFAULT_VERSION;
        $this->options = $options;
    }

    public function getClientId()
    {
        return $this->client_id;
    }

    public function getClientSecret()
    {
        return $this->client_secret;
    }

    public function setAccessToken($access_token)
    {
        $this->access_token = $access_token;
    }


    public function auth()
    {
        return new Auth($this);
    }

    /**
     * append client_id, timestamp, version, shop_id, access_token, sign to request
     *
     * @param RequestInterface $request
     * @return RequestInterface
     */
    protected function modifyRequestBeforeSend(RequestInterface $request)
    {
        $uri = $request->getUri();
        parse_str($uri->getQuery(), $query);

        $query['client_id'] = $this->getClientId();
        $query['timestamp'] = time();
        if ($this->access_token && !isset($query['Authorization'])) {
            $request = $request->withHeader('Authorization', $this->access_token);
        }
        $uri = $uri->withQuery(http_build_query($query));
        // set default content-type to application/json
        if (!$request->getHeaderLine('content-type')) {
            $request = $request->withHeader('content-type', 'application/json');
        }
        return $request->withUri($uri);
    }

    protected function httpClient()
    {
        $stack = HandlerStack::create();
        $stack->push(Middleware::mapRequest(function (RequestInterface $request) {
            return $this->modifyRequestBeforeSend($request);
        }));

        $options = array_merge([
            RequestOptions::HTTP_ERRORS => false, // disable throw exception on http 4xx, manual handle it
            'handler' => $stack,
            'base_uri' => 'https://sudd5dkvre.execute-api.us-east-1.amazonaws.com',
        ], $this->options ?? []);

        return new GuzzleHttpClient($options);
    }

    /**
     * Magic call resource
     *
     * @param $resourceName
     * @return mixed
     * @throws TransparencyException
     */
    public function __get($resourceName)
    {
        $resourceClassName = __NAMESPACE__."\\Resources\\".$resourceName;
        if (!in_array($resourceClassName, self::resources)) {
            throw new TransparencyException("Invalid resource ".$resourceName);
        }

        //Initiate the resource object
        $resource = new $resourceClassName();
        if (!$resource instanceof Resource) {
            throw new TransparencyException("Invalid resource class ".$resourceClassName);
        }
        $resource->useVersion($this->version);
        $resource->useHttpClient($this->httpClient());
        return $resource;
    }
}
